/**
 * File:   hmi.c
 * Author: AWTK Develop Team
 * Brief:  hmi client
 *
 * Copyright (c) 2023 - 2023  Guangzhou ZHIYUAN Electronics Co.,Ltd.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * License file for more details.
 *
 */

/**
 * History:
 * ================================================================
 * 2023-11-19 Li XianJing <xianjimli@hotmail.com> created
 *
 */

#include "hmi.h"
#include "tkc/mem.h"
#include "tkc/event.h"
#include "streams/serial/iostream_serial.h"

static ret_t hmi_on_model_events(void* ctx, event_t* e) {
  hmi_t* hmi = (hmi_t*)(ctx);
  prop_change_event_t* evt = prop_change_event_cast(e);
  return_value_if_fail(hmi != NULL && evt != NULL, RET_BAD_PARAMS);

  if (hmi->on_prop_changed != NULL) {
    hmi->on_prop_changed(hmi, evt->name, evt->value);
  }

  return RET_OK;
}

hmi_t* hmi_create(tk_iostream_t* io, hmi_on_prop_changed_t on_prop_changed, void* ctx) {
  hmi_t* hmi = NULL;
  remote_ui_t* remote_ui = NULL;
  return_value_if_fail(io != NULL, NULL);

  remote_ui = remote_ui_create(io);
  goto_error_if_fail(remote_ui != NULL);

  hmi = TKMEM_ZALLOC(hmi_t);
  goto_error_if_fail(hmi != NULL);

  hmi->ctx = ctx;
  hmi->remote_ui = remote_ui;
  hmi->on_prop_changed = on_prop_changed;
  remote_ui_on_event(remote_ui, STR_GLOBAL_MODEL, EVT_PROP_CHANGED, hmi_on_model_events, hmi);

  return hmi;
error:
  if (remote_ui != NULL) {
    remote_ui_destroy(remote_ui);
  }

  return NULL;
}

hmi_t* hmi_create_with_serial(const char* device, hmi_on_prop_changed_t on_prop_changed,
                              void* ctx) {
  tk_iostream_t* io = NULL;
  return_value_if_fail(device != NULL, NULL);
  io = tk_iostream_serial_create(device);
  return_value_if_fail(io != NULL, NULL);

  return hmi_create(io, on_prop_changed, ctx);
}

ret_t hmi_set_prop_int(hmi_t* hmi, const char* name, int32_t value) {
  value_t v;
  return_value_if_fail(name != NULL, RET_BAD_PARAMS);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, RET_BAD_PARAMS);

  value_set_int32(&v, value);

  return remote_ui_set_prop(hmi->remote_ui, STR_GLOBAL_MODEL, name, &v);
}

ret_t hmi_set_prop_str(hmi_t* hmi, const char* name, const char* value) {
  value_t v;
  return_value_if_fail(name != NULL, RET_BAD_PARAMS);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, RET_BAD_PARAMS);

  value_set_str(&v, value);

  return remote_ui_set_prop(hmi->remote_ui, STR_GLOBAL_MODEL, name, &v);
}

ret_t hmi_set_prop_bool(hmi_t* hmi, const char* name, bool_t value) {
  value_t v;
  return_value_if_fail(name != NULL, RET_BAD_PARAMS);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, RET_BAD_PARAMS);

  value_set_bool(&v, value);

  return remote_ui_set_prop(hmi->remote_ui, STR_GLOBAL_MODEL, name, &v);
}

ret_t hmi_set_prop_float(hmi_t* hmi, const char* name, float value) {
  value_t v;
  return_value_if_fail(name != NULL, RET_BAD_PARAMS);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, RET_BAD_PARAMS);

  value_set_float(&v, value);

  return remote_ui_set_prop(hmi->remote_ui, STR_GLOBAL_MODEL, name, &v);
}

ret_t hmi_set_prop_int64(hmi_t* hmi, const char* name, int64_t value) {
  value_t v;
  return_value_if_fail(name != NULL, RET_BAD_PARAMS);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, RET_BAD_PARAMS);

  value_set_int64(&v, value);

  return remote_ui_set_prop(hmi->remote_ui, STR_GLOBAL_MODEL, name, &v);
}

int32_t hmi_get_prop_int(hmi_t* hmi, const char* name, int32_t defvalue) {
  value_t v;
  return_value_if_fail(name != NULL, defvalue);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, defvalue);

  if (remote_ui_get_prop(hmi->remote_ui, STR_GLOBAL_MODEL, name, &v) == RET_OK) {
    return value_int32(&v);
  } else {
    return defvalue;
  }
}

bool_t hmi_get_prop_bool(hmi_t* hmi, const char* name, bool_t defvalue) {
  value_t v;
  return_value_if_fail(name != NULL, defvalue);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, defvalue);

  if (remote_ui_get_prop(hmi->remote_ui, STR_GLOBAL_MODEL, name, &v) == RET_OK) {
    return value_bool(&v);
  } else {
    return defvalue;
  }
}

float hmi_get_prop_float(hmi_t* hmi, const char* name, float defvalue) {
  value_t v;
  return_value_if_fail(name != NULL, defvalue);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, defvalue);

  if (remote_ui_get_prop(hmi->remote_ui, STR_GLOBAL_MODEL, name, &v) == RET_OK) {
    return value_float(&v);
  } else {
    return defvalue;
  }
}

const char* hmi_get_prop_str(hmi_t* hmi, const char* name, const char* defvalue) {
  value_t v;
  return_value_if_fail(name != NULL, defvalue);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, defvalue);

  if (remote_ui_get_prop(hmi->remote_ui, STR_GLOBAL_MODEL, name, &v) == RET_OK) {
    return value_str(&v);
  } else {
    return defvalue;
  }
}

int64_t hmi_get_prop_int64(hmi_t* hmi, const char* name, int64_t defvalue) {
  value_t v;
  return_value_if_fail(name != NULL, defvalue);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, defvalue);

  if (remote_ui_get_prop(hmi->remote_ui, STR_GLOBAL_MODEL, name, &v) == RET_OK) {
    return value_int64(&v);
  } else {
    return defvalue;
  }
}

ret_t hmi_get_prop(hmi_t* hmi, const char* target, const char* name, value_t* v) {
  return_value_if_fail(name != NULL && v != NULL, RET_BAD_PARAMS);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, RET_BAD_PARAMS);

  return remote_ui_get_prop(hmi->remote_ui, target, name, v);
}

ret_t hmi_set_prop(hmi_t* hmi, const char* target, const char* name, const value_t* v) {
  return_value_if_fail(name != NULL && v != NULL, RET_BAD_PARAMS);
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, RET_BAD_PARAMS);

  return remote_ui_set_prop(hmi->remote_ui, target, name, v);
}

ret_t hmi_dispatch(hmi_t* hmi) {
  ret_t ret = RET_OK;
  tk_object_t* io = NULL;
  return_value_if_fail(hmi != NULL && hmi->remote_ui != NULL, RET_BAD_PARAMS);

  io = TK_OBJECT(hmi->remote_ui->client.io);
  if (!tk_object_get_prop_bool(io, TK_STREAM_PROP_IS_OK, TRUE)) {
    return RET_IO;
  }

  while ((ret = tk_client_read_notify(&(hmi->remote_ui->client), 5)) == RET_OK) {
    remote_ui_dispatch(hmi->remote_ui);
  }

  return ret;
}

ret_t hmi_destroy(hmi_t* hmi) {
  return_value_if_fail(hmi != NULL, RET_BAD_PARAMS);

  if (hmi->remote_ui != NULL) {
    remote_ui_logout(hmi->remote_ui);
    remote_ui_destroy(hmi->remote_ui);
  }

  TKMEM_FREE(hmi);

  return RET_OK;
}
